package com.dhms.uikit

import android.content.Context
import android.media.MediaRecorder
import android.os.Build

import android.util.AttributeSet
import android.util.Log
import java.io.File
import java.io.IOException
import java.lang.Exception
import kotlin.math.roundToInt

class AudioRecordView : StopwatchView {
    private lateinit var _audioFile: String
    private var _audioRecordCallback: AudioRecordCallback? = null

    private var _recorder: MediaRecorder? = null

    /**
     * the callback for audio record event
     */
    var audioRecordCallback: AudioRecordCallback?
        get() = _audioRecordCallback
        set(value) {
            _audioRecordCallback = value
        }

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
        context,
        attrs,
        defStyle
    ) {
        init()
    }

    private fun init() {
    }

    /**
     * start audio record
     */
    fun start(fileName: String) {
        if (fileName.isEmpty()) {
            throw java.lang.IllegalArgumentException("No fileName is specified")
        }
        _audioFile = fileName
        if (super.getProcess() > 0) {
            super.stop()
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            _recorder = MediaRecorder(context)
        } else {
            @Suppress("DEPRECATION")
            _recorder = MediaRecorder()
        }
        _recorder?.apply {
            setAudioSource(MediaRecorder.AudioSource.DEFAULT)
            setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS)
            setOutputFile(fileName)
            setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
            try {
                prepare()
                start()
                Log.d(this.javaClass.simpleName, "start audio record")
                super.start()
            } catch (e: IOException) {
                super.stop()
                Log.e(this.javaClass.simpleName, "prepare() failed")
            }
        }
    }

    /**
     * stop started audio record
     */
    fun cancel() {
        stopAudioRecord()
        super.stop()
    }

    private fun stopAudioRecord() {
        try {
            _recorder?.stop()
            Log.d(this.javaClass.simpleName, "stop audio record")
        } catch (e: Exception) {
            Log.e(this.javaClass.simpleName, "stop() other error")
            // The internal error indicated that no valid audio data has been received
            // when stop. We need take action to clean up the output file
            if (File(_audioFile).exists()) {
                File(_audioFile).delete()
            }
            _audioRecordCallback?.apply {
                onCompleted(_audioFile, 0)
                _recorder = null
            }
        }
        _recorder?.release()
        _recorder?.let {
            val duration: Int = (super.timeDuration * super.getProcess()).roundToInt()
            _audioRecordCallback?.apply {
                onCompleted(_audioFile, duration)
                _recorder = null
            }
        }
    }

    // endregion
    interface AudioRecordCallback {
        fun onStarted()
        fun onCompleted(fileName: String, duration: Int)
    }
}
